﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Data.Linq;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Reflection;
using System.Threading;

using ZetaPrints.ZetaClient.Data;
using ZetaPrints.ZetaClient.Data.Repository.Linq;
using ZetaPrints.ZetaClient.Shared;
using ZetaPrints.ZetaClient.Shared.Manipulator;

namespace ZetaPrints.ZetaClient.Data.Repository
{
    /// <summary>
    /// The main class to take care of all database related changes
    /// </summary>
    public class DataRepositoryManager
    {
        #region private static attribute
        /// <summary>
        /// The lock for only one orderNumber to be given
        /// </summary>
        private static string _orderNumberLock = "_orderNumberLockEntry";
        /// <summary>
        /// The lock for only one entry at a time on the StatusLock
        /// </summary>
        private static string _orderStatusLock = "_orderStatusLock";
        /// <summary>
        /// Save the order lock
        /// </summary>
        private static string _saveOrderLock = "_saveOrderLock";
        /// <summary>
        /// The actual order number
        /// </summary>
        private static int _orderNumber = -1;
        #endregion


        #region private static property
        /// <summary>
        /// The property that gives out order number, if read it will
        /// give an unique order number
        /// </summary>
        private int NextOrderNumber
        {
            get
            {
                lock (_orderNumberLock)
                {
                    if (_orderNumber < 0)
                    {
                        /// get the highest number for a new record
                        var dbHighestOrderNumber = (from dbOrder in _zetaClientData.Order
                                                    orderby dbOrder.OrderNumber descending
                                                    select dbOrder.OrderNumber).Take(1);

                        if (dbHighestOrderNumber.Count() > 0)
                        {
                            _orderNumber = dbHighestOrderNumber.First() + 1;
                        }
                    }
                }

                return _orderNumber++;
            }
        }
        #endregion


        #region private attributes
        /// <summary>
        /// This is the connection to the database
        /// </summary>
        private ZetaClientData _zetaClientData;
        #endregion


        #region constructors
        public DataRepositoryManager()
        {
            /// get the data source from the xml file
            ZetaClientConfiguration zetaClientConfiguration = new ZetaClientConfiguration();

            if (!zetaClientConfiguration.IsDataSourceValid)
            {
                throw new InvalidDataException(Lang.DatabaseNotFound + "\n\r" + zetaClientConfiguration.DataSourceFile);
            }

            _zetaClientData = new ZetaClientData(zetaClientConfiguration.DataSource);


        }
        #endregion


        #region private methods
        #region status
        /// <summary>
        /// Saves or returns the orderstatusId
        /// </summary>
        /// <param name="xElement"></param>
        /// <returns></returns>
        private OrderStatus SaveOrderStatus(XElement xElement)
        {
            OrderStatus orderStatusEntry = null;

            var dataOrderStatus = (from orderStatus in _zetaClientData.OrderStatus
                                  where orderStatus.OrderStatusName == xElement.Attribute("Status").Value
                                  select orderStatus).Take(1);

            if (dataOrderStatus.Count() == 0)
            {
                /// locks the creation out, just one creation at a time.
                Monitor.Enter(_orderStatusLock);

                try
                {
                    /// get the information again.
                    dataOrderStatus = (from orderStatus in _zetaClientData.OrderStatus
                                       where orderStatus.OrderStatusName == xElement.Attribute("Status").Value
                                       select orderStatus).Take(1);

                    if (dataOrderStatus.Count() == 0)
                    {
                        #region nothing was returned create this new status
                        OrderStatus newOrderStatus = new OrderStatus();

                        /// create the new guy to go insise
                        newOrderStatus.OrderStatusName = xElement.Attribute("Status").Value;

                        /// save right now since this is a foreign key for the next record
                        _zetaClientData.OrderStatus.InsertOnSubmit(newOrderStatus);

                        orderStatusEntry = newOrderStatus;
                        #endregion
                    }
                    else
                    {
                        orderStatusEntry = dataOrderStatus.First();
                    }
                }
                finally
                {
                    /// this way we make sure this executes everytime
                    Monitor.Exit(_orderStatusLock);
                }
            }
            else
            {
                orderStatusEntry = dataOrderStatus.First();
            }

            return orderStatusEntry;
        }
        #endregion
        #region orderDetail
        /// <summary>
        /// Gets the Comments entries from the XML entry and 
        /// saves them to the database, the next submit to the
        /// database will get it
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="xSubElement"></param>
        private void SaveOrderCommentsDetail(Guid orderId, XElement xSubElement)
        {
            /// double check just in case
            if (xSubElement.Name == XmlNameOption.Comments.ToString())
            {
                #region orderCommentDetailList
                /// creata a list of the OrderCommentDetail so duplicates
                /// can be taken care of
                List<OrderCommentDetail> orderCommentDetailList = null;
                var dbOrderCommentDetail = from orderCommentDetailData in _zetaClientData.OrderCommentDetail
                                         where orderCommentDetailData.OrderId == orderId
                                         select orderCommentDetailData;
                /// initial index is used to mark where the old and the new items start
                int orderCommentDetailInitialIndex = dbOrderCommentDetail.Count();
                if (dbOrderCommentDetail.Count() > 0)
                {

                    orderCommentDetailList = new List<OrderCommentDetail>(dbOrderCommentDetail);
                }
                else
                {
                    orderCommentDetailList = new List<OrderCommentDetail>();
                }
                #endregion

                /// go through each element within the Comments
                foreach (XElement xCommentDetail in xSubElement.Elements())
                {
                    if (XmlManipulator.AttributeHasValue(xCommentDetail))
                    {
                        /// start as a null, since we do not know if this is a new
                        /// entry or a duplicate been updated
                        OrderCommentDetail orderCommentDetail = null;

                        /// get the list of OrderCommentDetail to find duplicates
                        var dbOrderCommentDetailItem = from orderCommentDetailData in orderCommentDetailList
                                                     where orderCommentDetailData.OrderId == orderId &&
                                                           orderCommentDetailData.Xml == xCommentDetail.ToString()
                                                     select orderCommentDetailData;

                        /// there is already this item in the system. Do not 
                        /// do anythign at all if already exists
                        if (dbOrderCommentDetailItem.Count() == 0)
                        {
                            orderCommentDetail = new OrderCommentDetail();
                            orderCommentDetail.OrderId = orderId;
                            orderCommentDetail.CommentIndex = orderCommentDetailList.Count();

                            if (xCommentDetail.Attribute("Comment") != null)
                            {
                                orderCommentDetail.Comment = xCommentDetail.Attribute("Comment").Value.ToString();
                            }

                            orderCommentDetail.Xml = xCommentDetail.ToString();

                            orderCommentDetailList.Add(orderCommentDetail);
                        }
                    }
                }

                /// only insert records which are new
                for (int count = orderCommentDetailInitialIndex; count < orderCommentDetailList.Count - orderCommentDetailInitialIndex; count++)
                {
                    _zetaClientData.OrderCommentDetail.InsertOnSubmit(orderCommentDetailList[count]);
                }

                _zetaClientData.SubmitChanges();
            }
            else
            {
                throw new InvalidProgramException("The SaveOrderCommentDetail was called, but this is not a OrderCommentDetail xml node \n" +
                    "XmlNode:" + xSubElement.Name.ToString());
            }
        }
        /// <summary>
        /// Gets the Fields entries from the XML entry and 
        /// saves them to the database, the next submit to the
        /// database will get it
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="xSubElement"></param>
        private void SaveOrderFieldsDetail(Guid orderId, XElement xSubElement)
        {
            /// double check just in case
            if (xSubElement.Name == XmlNameOption.Fields.ToString())
            {
                #region orderFieldDetailList
                /// creata a list of the OrderFieldDetail so duplicates
                /// can be taken care of
                List<OrderFieldDetail> orderFieldDetailList = null;
                var dbOrderFieldDetail = from orderFieldDetailData in _zetaClientData.OrderFieldDetail
                                           where orderFieldDetailData.OrderId == orderId
                                           select orderFieldDetailData;
                /// initial index is used to mark where the old and the new items start
                int orderFieldDetailInitialIndex = dbOrderFieldDetail.Count();
                if (dbOrderFieldDetail.Count() > 0)
                {

                    orderFieldDetailList = new List<OrderFieldDetail>(dbOrderFieldDetail);
                }
                else
                {
                    orderFieldDetailList = new List<OrderFieldDetail>();
                }
                #endregion

                /// go through each element within the Comments
                foreach (XElement xFieldDetail in xSubElement.Elements())
                {
                    if (XmlManipulator.AttributeHasValue(xFieldDetail))
                    {
                        /// start as a null, since we do not know if this is a new
                        /// entry or a duplicate been updated
                        OrderFieldDetail orderFieldDetail = null;

                        /// get the list of OrderFieldDetail to find duplicates
                        var dbOrderFieldDetailItem = from orderFieldDetailData in orderFieldDetailList
                                                       where orderFieldDetailData.OrderId == orderId &&
                                                             orderFieldDetailData.Xml == xFieldDetail.ToString()
                                                       select orderFieldDetailData;

                        /// there is already this item in the system. Do not 
                        /// do anythign at all if already exists
                        if (dbOrderFieldDetailItem.Count() == 0)
                        {
                            orderFieldDetail = new OrderFieldDetail();
                            orderFieldDetail.OrderId = orderId;
                            orderFieldDetail.FieldIndex = orderFieldDetailList.Count();

                            if (xFieldDetail.Attribute("Name") != null)
                            {
                                orderFieldDetail.Name = xFieldDetail.Attribute("Name").Value.ToString();
                            }
                            if (xFieldDetail.Attribute("Value") != null)
                            {
                                orderFieldDetail.Value = xFieldDetail.Attribute("Value").Value;
                            }
                            if (xFieldDetail.Attribute("Comment") != null)
                            {
                                orderFieldDetail.Comment = xFieldDetail.Attribute("Comment").Value;
                            }

                            orderFieldDetail.Xml = xFieldDetail.ToString();

                            orderFieldDetailList.Add(orderFieldDetail);
                        }
                    }
                }

                /// only insert records which are new
                for (int count = orderFieldDetailInitialIndex; count < orderFieldDetailList.Count - orderFieldDetailInitialIndex; count++)
                {
                    _zetaClientData.OrderFieldDetail.InsertOnSubmit(orderFieldDetailList[count]);
                }

                _zetaClientData.SubmitChanges();
            }
            else
            {
                throw new InvalidProgramException("The SaveOrderFieldDetail was called, but this is not a OrderFieldDetail xml node \n" +
                    "XmlNode:" + xSubElement.Name.ToString());
            }
        }
        /// <summary>
        /// Gets the Fonts entries from the XML entry and 
        /// saves them to the database, the next submit to the
        /// database will get it
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="xSubElement"></param>
        private void SaveOrderFontsDetail(Guid orderId, XElement xSubElement)
        {
            /// double check just in case
            if (xSubElement.Name == XmlNameOption.Fonts.ToString())
            {
                #region orderFontDetailList
                /// creata a list of the OrderFontDetail so duplicates
                /// can be taken care of
                List<OrderFontDetail> orderFontDetailList = null;
                var dbOrderFontDetail = from orderFontDetailData in _zetaClientData.OrderFontDetail
                                         where orderFontDetailData.OrderId == orderId
                                         select orderFontDetailData;
                /// initial index is used to mark where the old and the new items start
                int orderFontDetailInitialIndex = dbOrderFontDetail.Count();
                if (dbOrderFontDetail.Count() > 0)
                {

                    orderFontDetailList = new List<OrderFontDetail>(dbOrderFontDetail);
                }
                else
                {
                    orderFontDetailList = new List<OrderFontDetail>();
                }
                #endregion

                /// go through each element within the Comments
                foreach (XElement xFontDetail in xSubElement.Elements())
                {
                    if (XmlManipulator.AttributeHasValue(xFontDetail))
                    {
                        /// start as a null, since we do not know if this is a new
                        /// entry or a duplicate been updated
                        OrderFontDetail orderFontDetail = null;

                        /// get the list of OrderFontDetail to find duplicates
                        var dbOrderFontDetailItem = from orderFontDetailData in orderFontDetailList
                                                     where orderFontDetailData.OrderId == orderId &&
                                                           orderFontDetailData.Xml == xFontDetail.ToString()
                                                     select orderFontDetailData;

                        /// there is already this item in the system. Do not 
                        /// do anythign at all if already exists
                        if (dbOrderFontDetailItem.Count() == 0)
                        {
                            orderFontDetail = new OrderFontDetail();
                            orderFontDetail.OrderId = orderId;
                            orderFontDetail.FontIndex = orderFontDetailList.Count();

                            if (xFontDetail.Attribute("Name") != null)
                            {
                                orderFontDetail.Name = xFontDetail.Attribute("Name").Value.ToString();
                            }

                            orderFontDetail.Xml = xFontDetail.ToString();

                            orderFontDetailList.Add(orderFontDetail);
                        }
                    }
                }

                /// only insert records which are new
                for (int count = orderFontDetailInitialIndex; count < orderFontDetailList.Count - orderFontDetailInitialIndex; count++)
                {
                    _zetaClientData.OrderFontDetail.InsertOnSubmit(orderFontDetailList[count]);
                }

                _zetaClientData.SubmitChanges();
            }
            else
            {
                throw new InvalidProgramException("The SaveOrderFontDetail was called, but this is not a OrderFontDetail xml node \n" +
                    "XmlNode:" + xSubElement.Name.ToString());
            }
        }
        /// <summary>
        /// Will try to get a OrderFileDetail typeId, if one
        /// is not found it will create one on the database
        /// and return it.
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        private OrderFileDetailType GetOrderFileDetailTypeId(string typeName)
        {
            OrderFileDetailType orderFileDetailTypeEntry = new OrderFileDetailType();

            var orderFileDetailType = (from orderFileDetailTypeItem in _zetaClientData.OrderFileDetailType
                                       where orderFileDetailTypeItem.FileTypeName == typeName
                                       select orderFileDetailTypeItem).Take(1);

            if (orderFileDetailType.Count() == 0)
            {
                /// create the new entry
                orderFileDetailTypeEntry.FileTypeName = typeName;

                /// insert the subimtion later
                _zetaClientData.OrderFileDetailType.InsertOnSubmit(orderFileDetailTypeEntry);
            }
            else
            {
                /// the first item must be it since we got a hit
                orderFileDetailTypeEntry = orderFileDetailType.First();
            }

            return orderFileDetailTypeEntry;
        }
        /// <summary>
        /// Gets the Images entries from the XML entry and 
        /// saves them to the database, the next submit to the
        /// database will get it
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="xSubElement"></param>
        private bool SaveOrderFileDetail(Guid orderId, XElement xSubElement, List<OrderFileDetail> orderFileDetailList, int fileIndex)
        {
            bool entryAdded = false;

            if (xSubElement != null)
            {
                if ((xSubElement.Name == XmlNameOption.Image.ToString()) ||
                    (xSubElement.Name == XmlNameOption.Page.ToString()) ||
                    (xSubElement.Name == XmlNameOption.File.ToString()))
                {
                    //// is there any information?
                    if (XmlManipulator.AttributeHasValue(xSubElement))
                    {
                        /// the name of the file entry
                        string name = string.Empty;

                        /// we must be unique by web path for this order, since 
                        /// a duplicate entry would mean duplicate
                        string webPath = string.Empty;

                        /// save the xml
                        string xml = xSubElement.ToString();

                        if (xSubElement.Name == XmlNameOption.Image.ToString())
                        {
                            #region image xml parsed
                            if (xSubElement.Attribute("Name") != null)
                            {
                                name = xSubElement.Attribute("Name").Value.ToString();
                            }

                            if (xSubElement.Attribute("OriginalName") != null)
                            {
                                webPath = xSubElement.Attribute("OriginalName").Value;

                                if (name == string.Empty)
                                {
                                    name = StringManipulator.GetFileNameFromWebPath(webPath);
                                }
                            }
                            #endregion
                        }
                        else if (xSubElement.Name == XmlNameOption.Page.ToString())
                        {
                            #region page xml parsed

                            if (xSubElement.Attribute("Name") != null)
                            {
                                name = xSubElement.Attribute("Name").Value.ToString();
                            }

                            if (xSubElement.Attribute("user-preview") != null)
                            {
                                webPath = xSubElement.Attribute("user-preview").Value.ToString();

                                if (name == string.Empty)
                                {
                                    name = StringManipulator.GetFileNameFromWebPath(webPath);
                                }
                            }
                            else if (xSubElement.Attribute("PreviewImage") != null)
                            {
                                webPath = xSubElement.Attribute("PreviewImage").Value.ToString();

                                if (name == string.Empty)
                                {
                                    name = StringManipulator.GetFileNameFromWebPath(webPath);
                                }
                            }
                            #endregion
                        }
                        else if (xSubElement.Name == XmlNameOption.File.ToString())
                        {
                            name = xSubElement.Attribute("name").Value;
                            webPath = xSubElement.Attribute("webpath").Value;
                        }

                        /// do we have any thing at all? if not go on without it
                        if (webPath.Length > 0)
                        {
                            /// this is the object that will be modifed or added
                            OrderFileDetail orderFileDetail = null;

                            /// get to see if we have a duplicate
                            var dbOrderFileDetailItem = from orderFileDetailData in orderFileDetailList
                                                        where orderFileDetailData.WebPath == webPath &&
                                                               orderFileDetailData.OrderId == orderId
                                                        select orderFileDetailData;

                            if (dbOrderFileDetailItem.Count() == 1)
                            {
                                /// this is a duplicate time to update the information
                                orderFileDetail = dbOrderFileDetailItem.First();
                                orderFileDetail.Name = name;
                                orderFileDetail.Xml = xml;
                                orderFileDetail.OrderFileDetailType = GetOrderFileDetailTypeId(xSubElement.Name.ToString());
                            }
                            else if (dbOrderFileDetailItem.Count() == 0)
                            {
                                /// creating a new entry to be added
                                orderFileDetail = new OrderFileDetail();
                                orderFileDetail.OrderId = orderId;
                                orderFileDetail.FileIndex = fileIndex;
                                orderFileDetail.Name = name;
                                orderFileDetail.WebPath = webPath;
                                orderFileDetail.Xml = xml;
                                orderFileDetail.OrderFileDetailType = GetOrderFileDetailTypeId(xSubElement.Name.ToString());

                                entryAdded = true;

                                _zetaClientData.OrderFileDetail.InsertOnSubmit(orderFileDetail);
                            }
                            else
                            {
                                string errorString = string.Empty;

                                foreach (OrderFileDetail orderFileDetailEntry in dbOrderFileDetailItem)
                                {
                                    errorString += orderFileDetailEntry.OrderId.ToString() + "," +
                                        orderFileDetailEntry.FileIndex + "," +
                                        orderFileDetailEntry.WebPath + "," +
                                        orderFileDetailEntry.Xml + "\n";
                                }

                                throw new DataMisalignedException("on db order there is more than one file that matches OrderId and WebPath, " +
                                    "creating a duplicate entry:\n" + errorString);
                            }
                        }
                    }
                }
                                
                _zetaClientData.SubmitChanges();
            }

            return entryAdded;
        }
        /// <summary>
        /// Gets the PayPal entries from the XML entry and 
        /// saves them to the database, the next submit to the
        /// database will get it
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="xSubElement"></param>
        private void SaveOrderPayPalDetail(Guid orderId, XElement xSubElement)
        {
            /// double check just in case
            if (xSubElement.Name == XmlNameOption.PayPal.ToString())
            {
                #region orderPayPalDetailList
                /// creata a list of the OrderPayPalDetail so duplicates
                /// can be taken care of
                List<OrderPayPalDetail> orderPayPalDetailList = null;
                var dbOrderPayPalDetail = from orderPayPalDetailData in _zetaClientData.OrderPayPalDetail
                                        where orderPayPalDetailData.OrderId == orderId
                                        select orderPayPalDetailData;
                /// initial index is used to mark where the old and the new items start
                int orderPayPalDetailInitialIndex = dbOrderPayPalDetail.Count();
                if (dbOrderPayPalDetail.Count() > 0)
                {

                    orderPayPalDetailList = new List<OrderPayPalDetail>(dbOrderPayPalDetail);
                }
                else
                {
                    orderPayPalDetailList = new List<OrderPayPalDetail>();
                }
                #endregion

                /// go through each element within the Comments
                foreach (XElement xPayPalDetail in xSubElement.Elements())
                {
                    if (XmlManipulator.AttributeHasValue(xPayPalDetail))
                    {
                        /// start as a null, since we do not know if this is a new
                        /// entry or a duplicate been updated
                        OrderPayPalDetail orderPayPalDetail = null;

                        /// get the list of OrderPayPalDetail to find duplicates
                        var dbOrderPayPalDetailItem = from orderPayPalDetailData in orderPayPalDetailList
                                                    where orderPayPalDetailData.OrderId == orderId &&
                                                          orderPayPalDetailData.Xml == xPayPalDetail.ToString()
                                                    select orderPayPalDetailData;

                        /// there is already this item in the system. Do not 
                        /// do anythign at all if already exists
                        if (dbOrderPayPalDetailItem.Count() == 0)
                        {
                            orderPayPalDetail = new OrderPayPalDetail();
                            orderPayPalDetail.OrderId = orderId;

                            orderPayPalDetail.Xml = xPayPalDetail.ToString();

                            orderPayPalDetailList.Add(orderPayPalDetail);
                        }
                    }
                }

                /// only insert records which are new
                for (int count = orderPayPalDetailInitialIndex; count < orderPayPalDetailList.Count - orderPayPalDetailInitialIndex; count++)
                {
                    _zetaClientData.OrderPayPalDetail.InsertOnSubmit(orderPayPalDetailList[count]);
                }

                _zetaClientData.SubmitChanges();
            }
            else
            {
                throw new InvalidProgramException("The SaveOrderPayPalDetail was called, but this is not a OrderPayPalDetail xml node \n" +
                    "XmlNode:" + xSubElement.Name.ToString());
            }
        }
        #endregion
        #endregion


        #region public methods
        #region delete
        /// <summary>
        /// Deletes a site basing only on the 
        /// site name
        /// </summary>
        /// <param name="siteName"></param>
        /// <returns></returns>
        public void DeleteSite(Site siteEntry)
        {
            var site = from sitedb in _zetaClientData.Site
                       where sitedb.SiteId == siteEntry.SiteId
                       select sitedb;


            if (site.Count() > 0)
            {
                foreach (Order order in site.First().Order)
                {
                    DeleteOrder(order);
                }

                _zetaClientData.Site.DeleteOnSubmit(site.First());

                _zetaClientData.SubmitChanges();
            }
        }
        public void DeleteOrder(Order order)
        {
            foreach (OrderCommentDetail orderCommentDetail in order.OrderCommentDetail)
            {
                _zetaClientData.OrderCommentDetail.DeleteOnSubmit(orderCommentDetail);
            }
            foreach (OrderFieldDetail orderFieldDetail in order.OrderFieldDetail)
            {
                _zetaClientData.OrderFieldDetail.DeleteOnSubmit(orderFieldDetail);
            }
            foreach (OrderFileDetail orderFileDetail in order.OrderFileDetail)
            {
                DeleteOrderFieldDetail(orderFileDetail);
            }
            foreach (OrderFontDetail orderFontDetail in order.OrderFontDetail)
            {
                _zetaClientData.OrderFontDetail.DeleteOnSubmit(orderFontDetail);
            }
            foreach (OrderPayPalDetail orderPaypalDetail in order.OrderPayPalDetail)
            {
                _zetaClientData.OrderPayPalDetail.DeleteOnSubmit(orderPaypalDetail);
            }
            
            _zetaClientData.Order.DeleteOnSubmit(order);
        }
        /// <summary>
        /// We delete the record and the files with the records
        /// </summary>
        /// <param name="orderFileDetail"></param>
        public void DeleteOrderFieldDetail(OrderFileDetail orderFileDetail)
        {
            if (orderFileDetail.LocalPath != null)
            {
                /// delete the file associated to the order
                if (File.Exists(orderFileDetail.LocalPath))
                {
                    File.Delete(orderFileDetail.LocalPath);
                }

                string directoryPath = orderFileDetail.LocalPath.Substring(0, orderFileDetail.LocalPath.LastIndexOf('\\'));

                /// if the directory is empty we must delete the directory also.
                /// the directory must be empty first
                if ((Directory.GetFiles(directoryPath).Length == 0) && (Directory.GetDirectories(directoryPath).Length == 0))
                {
                    Directory.Delete(directoryPath);
                }
            }

            /// delete the file record
            _zetaClientData.OrderFileDetail.DeleteOnSubmit(orderFileDetail);
        }
        #endregion
        #region fetch
        #region site
        /// <summary>
        /// Gets all sites within the database
        /// </summary>
        /// <returns></returns>
        public List<Site> FetchSites()
        {
            List<Site> siteList = new List<Site>();

            /// get all the sites form the database
            var siteDataList = from sites in _zetaClientData.Site
                               select sites;

            /// transfer the information to the list format. Only if
            /// we have at least one entry
            if (siteDataList.Count() > 0)
            {
                siteList = new List<Site>(siteDataList.ToArray());
            }


            return siteList;
        }
        /// <summary>
        /// Gets a Site object from a siteId number
        /// </summary>
        /// <param name="siteId"></param>
        /// <returns></returns>
        public Site FetchSite(int siteId)
        {
            Site siteEntry = null;

            var sitedata = (from site in _zetaClientData.Site
                            where site.SiteId == siteId
                            select site).Take(1);

            if (sitedata.Count() > 0)
            {
                siteEntry = sitedata.First();
            }

            return siteEntry;
        }
        /// <summary>
        /// Gets a Site object from a siteId number
        /// </summary>
        /// <param name="siteId"></param>
        /// <returns></returns>
        public Site FetchSite(string siteName)
        {
            Site siteEntry = null;

            var sitedata = (from site in _zetaClientData.Site
                            where site.SiteName == siteName
                            select site).Take(1);

            if (sitedata.Count() > 0)
            {
                siteEntry = sitedata.First();
            }

            return siteEntry;
        }
        #endregion
        #region order
        /// <summary>
        /// Fetches the order by the Order Id given
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        public Order FetchOrder(Guid orderId)
        {
            Order returnOrder = null;

            var orderData = from order in _zetaClientData.Order
                            where order.OrderId == orderId
                            select order;

            if (orderData.Count() > 0)
            {
                returnOrder = orderData.First();
            }

            return returnOrder;
        }
        public OrderFileDetail FetchOrderFileDetail(Guid orderId, int fileIndex)
        {
            OrderFileDetail orderFileDetailRecord = null;

            var orderFileDetailData = from orderFileDetail in _zetaClientData.OrderFileDetail
                                      where orderFileDetail.OrderId == orderId && orderFileDetail.FileIndex == fileIndex
                                      select orderFileDetail;

            return (OrderFileDetail)orderFileDetailRecord;
        }
        /// <summary>
        /// Gets the list of OrderImageDetails based on the siteid and orderId combination
        /// </summary>
        /// <param name="siteId"></param>
        /// <param name="orderId"></param>
        /// <returns></returns>
        public List<OrderFileDetail> FetchOrderFileDetailList(Guid orderId)
        {
            var orderFileDetailData = from orderFileDetail in _zetaClientData.OrderFileDetail
                                       where orderFileDetail.OrderId == orderId
                                       select orderFileDetail;

            return new List<OrderFileDetail>(orderFileDetailData);
        }
        /// <summary>
        /// Saves the information to the database
        /// </summary>
        /// <param name="orderId"></param>
        /// <param name="fileIndex"></param>
        /// <param name="localPath"></param>
        public void SaveOrderFileDetailLocalPath(Guid orderId, int fileIndex, string localPath)
        {
            var orderFileDetail = (from orderFileDetailDb in _zetaClientData.OrderFileDetail
                                  where orderFileDetailDb.OrderId == orderId &&
                                        orderFileDetailDb.FileIndex == fileIndex
                                  select orderFileDetailDb).Take(1);

            if (orderFileDetail.Count() > 0)
            {
                orderFileDetail.First().LocalPath = localPath;
                _zetaClientData.SubmitChanges();
            }
        }
        /// <summary>
        /// Get orders
        /// </summary>
        /// <param name="siteId"></param>
        /// <param name="startDateTime"></param>
        /// <returns></returns>
        public List<Order> FetchOrders(int siteId, DateTime startDateTime)
        {
            List<Order> orderList = new List<Order>();

            var orderData = from order in _zetaClientData.Order
                            join orderStatus in _zetaClientData.OrderStatus on order.OrderStatusId equals orderStatus.OrderStatusId
                            orderby order.OrderNumber ascending
                            where order.SiteId == siteId && order.Created > startDateTime
                            select order;

            if (orderData.Count() > 0)
            {
                orderList = orderData.ToList();
            }

            return orderList;
        }
        /// <summary>
        /// Fetches all the orders within a site id
        /// </summary>
        /// <param name="siteId"></param>
        /// <returns></returns>
        public List<Order> FetchOrders(int siteId)
        {
            List<Order> orderList = new List<Order>();

            var orderData = from order in _zetaClientData.Order
                            join orderStatus in _zetaClientData.OrderStatus on order.OrderStatusId equals orderStatus.OrderStatusId
                            orderby order.OrderNumber ascending
                            where order.SiteId == siteId
                            select order;

            if (orderData.Count() > 0)
            {
                orderList = orderData.ToList();
            }

            return orderList;
        }
        /// <summary>
        /// Fetches the order header with the highest date time and time.
        /// </summary>
        /// <param name="siteId"></param>
        /// <returns></returns>
        public DateTime FetchLastOrderHeaderDateTime(int siteId)
        {
            /// the detaulf is going to be 1/1/2000 at 00:00
            DateTime dateTime = new DateTime(2000, 1, 1, 0, 0, 0);

            var youghestDateTime = (from order in _zetaClientData.Order
                                    where order.SiteId == siteId
                                    orderby order.Created descending
                                    select order.Created).Take(1);

            /// did we get any records?
            if (youghestDateTime.Count() > 0)
            {
                dateTime = youghestDateTime.First();
            }

            return dateTime;
        }
        #endregion
        #region order status
        /// <summary>
        /// Gets all the order status from the database
        /// </summary>
        /// <returns></returns>
        public List<OrderStatus> FetchOrderStatusList()
        {
            List<OrderStatus> orderStatusList = new List<OrderStatus>();


            var dbOrderStatus = from orderStatus in _zetaClientData.OrderStatus
                                select orderStatus;

            /// did we get at least one item back?
            if (dbOrderStatus.Count() > 0)
            {
                orderStatusList = new List<OrderStatus> ( dbOrderStatus );
            }


            return orderStatusList;
        }
        #endregion
        #endregion
        #region save
        #region site
        /// <summary>
        /// Saves a site to the database, check will be done for
        /// duplicates. Updates will be done automatically. This
        /// will call Submit Changes imeditaly
        /// </summary>
        /// <param name="siteItem"></param>
        /// <returns></returns>
        public bool SaveSite(Site siteItem)
        {
            bool itemSaved = false;

            /// check to see if this is an update or an insert
            var siteData = from site in _zetaClientData.Site
                           where site.SiteName == siteItem.SiteName
                           select site;

            if (siteData.Count() > 0)
            {
                /// we found an item that is similar to ours.
                /// Just replace the ApiKey if it is not the same
                if (siteItem.ApiKey != siteData.First().ApiKey)
                {
                    siteData.First().ApiKey = siteItem.ApiKey;
                }
            }
            else
            {
                /// we create a new item
                _zetaClientData.Site.InsertOnSubmit(siteItem);
            }

            _zetaClientData.SubmitChanges();

            return itemSaved;
        }
        #endregion
        #region order
        /// <summary>
        /// Saves an order
        /// </summary>
        /// <param name="xElement"></param>
        /// <returns></returns>
        public bool SaveOrder(int siteId, XElement xElement)
        {
            bool dataSaved = false;

            if (xElement.Name == XmlNameOption.Order.ToString())
            {
                /// if this is a new record we need to add
                /// to the database, or else we are just
                /// going to update it
                bool newRecord = true;

                Guid orderIdGuid = new Guid(xElement.Attribute("OrderID").Value);

                var dbOrderResult = (from dbOrder in _zetaClientData.Order
                                    where dbOrder.OrderId == orderIdGuid
                                    select dbOrder).Take(1);


                /// now we will knwo if this is an update or a new entry
                Order order = null;

                if (dbOrderResult.Count() == 0)
                {
                    order = new Order();
                    order.OrderId = orderIdGuid;
                    order.OrderNumber = NextOrderNumber;
                }
                else
                {
                    order = dbOrderResult.First();
                    newRecord = false;
                }

                List<PropertyInfo> propertyList = new List<PropertyInfo>(order.GetType().GetProperties());

                order.SiteId = siteId;
                order.CreatedBy = xElement.Attribute("CreatedBy").Value;
                order.Created = ZetaDateTimeStringManipulator.ToDateTime(xElement.Attribute("Created").Value);
                order.OrderStatus = SaveOrderStatus(xElement);
                if (xElement.Attribute("Balance") != null)
                {
                    order.Balance = Convert.ToDecimal(xElement.Attribute("Balance").Value);
                }

                if (newRecord)
                {
                    _zetaClientData.Order.InsertOnSubmit(order);
                    dataSaved = true;
                }

                /// only one submit at a time.
                lock (_saveOrderLock)
                {
                    _zetaClientData.SubmitChanges();
                }

                dataSaved = true;
            }

            return dataSaved;
        }
        /// <summary>
        /// Saves the contents of an OrderList
        /// </summary>
        /// <param name="xElement"></param>
        /// <returns>true if all data was saved</returns>
        public bool SaveOrderList(int siteId, XElement xElement)
        {
            bool dataSaved = false;

            if (xElement.Name == XmlNameOption.OrderList.ToString())
            {
                foreach (XElement xOrder in xElement.Elements())
                {
                    SaveOrder(siteId, xOrder);
                }
            }

            return dataSaved;
        }
        #endregion
        #region order detail
        /// <summary>
        /// Saves the detail of the order
        /// </summary>
        /// <param name="OrderId">Order id that </param>
        /// <param name="xElement"></param>
        /// <returns></returns>
        public bool SaveOrderDetail(int siteId, XElement xElement)
        {
            bool dataSaved = false;

            if (xElement.Name == "OrderDetails")
            {
                /// the order id of this entry
                Guid orderId = new Guid(xElement.Attribute(XmlNameOption.OrderID.ToString()).Value);

                /// the file index of the OrderFile
                int fileIndex = 0;

                #region get order file
                /// creata a list of the OrderImageDetail so duplicates
                /// can be taken care of
                List<OrderFileDetail> orderFileDetailList = null;
                var dbOrderFileDetail = from orderFileDetail in _zetaClientData.OrderFileDetail
                                        where orderFileDetail.OrderId == orderId
                                        select orderFileDetail;

                /// initial index is used to mark where the old and the new items start
                int orderImageDetailInitialIndex = dbOrderFileDetail.Count();
                if (dbOrderFileDetail.Count() > 0)
                {
                    orderFileDetailList = new List<OrderFileDetail>(dbOrderFileDetail);
                    fileIndex = orderFileDetailList.Count;
                }
                else
                {
                    orderFileDetailList = new List<OrderFileDetail>();
                }
                #endregion

                /// Get teh xml that will go on the Order itself
                XElement xmlOrderDetail = new XElement("XmlOrderDetail");
                XElement xmlUserDetail = new XElement("UserDetails");
                
                XElement xFile = new XElement("OrderFileDetail");

                /// get the items that will go on the order itself
                foreach (XAttribute xAttribute in xElement.Attributes())
                {
                    xmlOrderDetail.Add(xAttribute);

                    if ((xAttribute.Name == "CDR") ||
                        (xAttribute.Name == "PDF") ||
                        (xAttribute.Name == "GIF") ||
                        (xAttribute.Name == "PNG") ||
                        (xAttribute.Name == "JPEG"))
                    {
                        XElement file = new XElement("File",
                            new XAttribute("name", StringManipulator.GetFileNameFromWebPath(xAttribute.Value)),
                            new XAttribute("webpath", xAttribute.Value));

                        xFile.Add(file);
                    }
                }

                foreach (XElement xFileEntry in xFile.Elements())
                {
                    if (SaveOrderFileDetail(orderId, xFileEntry, orderFileDetailList, fileIndex))
                    {
                        /// we got a new record increate this sucker
                        fileIndex++;
                    }
                }

                /// now fill up those items in the list
                foreach (XElement xSubElement in xElement.Elements())
                {
                    if (xSubElement.Name == XmlNameOption.Comments.ToString())
                    {
                        SaveOrderCommentsDetail(orderId, xSubElement);
                    }
                    else if (xSubElement.Name == XmlNameOption.Fields.ToString())
                    {
                        SaveOrderFieldsDetail(orderId, xSubElement);
                    }
                    else if (xSubElement.Name == XmlNameOption.Fonts.ToString())
                    {
                        SaveOrderFontsDetail(orderId, xSubElement);
                    }
                    else if ((xSubElement.Name == XmlNameOption.Images.ToString()) || (xSubElement.Name == XmlNameOption.Pages.ToString()))
                    {
                        /// go to the sub entries
                        foreach (XElement xItem in xSubElement.Elements())
                        {
                            if (SaveOrderFileDetail(orderId, xItem, orderFileDetailList, fileIndex))
                            {
                                fileIndex++;
                            }
                        }
                    }
                    else if (xSubElement.Name == XmlNameOption.PayPal.ToString())
                    {
                        SaveOrderPayPalDetail(orderId, xSubElement);
                    }
                    else if (xSubElement.Name == XmlNameOption.UserDetails.ToString())
                    {
                        xmlUserDetail = xSubElement;
                    }
                    else
                    {
                        throw new InvalidProgramException("The entry on the xml was not implemented on the system\n" +
                            "EntryName:" + xSubElement.Name.ToString());
                    }
                }

                /// get the order to be modified
                var addDetailToOrder = (from order in _zetaClientData.Order
                                        where order.OrderId == orderId && order.SiteId == siteId
                                        select order).Take(1);

                if (addDetailToOrder.Count() > 0)
                {
                    OrderStatus orderStatus = SaveOrderStatus(xmlOrderDetail);

                    /// if the status id has changed update it.
                    if (addDetailToOrder.First().OrderStatusId != orderStatus.OrderStatusId)
                    {
                        addDetailToOrder.First().OrderStatus = orderStatus;
                    }

                    addDetailToOrder.First().XmlOrderDetail = xmlOrderDetail.ToString();
                    addDetailToOrder.First().XmlUserDetail = xmlUserDetail.ToString();
                                        
                    _zetaClientData.SubmitChanges();
                    
                    dataSaved = true;
                }
            }

            return dataSaved;
        }
        #endregion
        #endregion
        #region update
        /// <summary>
        /// Submit changes to any object that came from the data level.
        /// </summary>
        public void SubmitChanges()
        {
            _zetaClientData.SubmitChanges();
        }
        #region order detail
        /// <summary>
        /// Will return true if no other record is using this files
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public bool IsExclusiveFile(string source)
        {
            bool exclusiveFile = true;

            /// check how many records we got matching this source
            var recordCount = (from orderFileDetail in _zetaClientData.OrderFileDetail
                        where orderFileDetail.LocalPath == source
                        select orderFileDetail).Count();

            /// if we got more than one record with 
            /// this entry than we have an e
            if (recordCount > 1)
            {
                exclusiveFile = false;
            }

            return exclusiveFile;
        }
        /// <summary>
        /// Changes the file detail entry from one location
        /// to another
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <returns></returns>
        public bool ChangeFileDetailLocalPath(Guid orderId, int fileIndex, string source, string destination)
        {
            bool entryChanged = false;

            /// get all the files that have the local path and order id combination
            var orderFileDetailData = from orderFileDetail in _zetaClientData.OrderFileDetail
                       where orderFileDetail.OrderId == orderId &&
                             orderFileDetail.FileIndex == fileIndex &&
                             orderFileDetail.LocalPath == source
                       select orderFileDetail;

            /// we must have gotten only one record
            if (orderFileDetailData.Count() == 1)
            {
                orderFileDetailData.First().LocalPath = destination;
                entryChanged = true;
            }

            return entryChanged;
        }
        #endregion
        #endregion
        #endregion
    }
}
